﻿#include <PlatformStruct.h>
#include "DatabaseOperator.h"
#include "../FacilityBaseLib/Instrument.h"
#include "../FacilityBaseLib/InstrumentInfo.h"
#include "../FacilityBaseLib/Container.h"
#include "../FacilityBaseLib/StringMgr.h"
#include <cassert>
#include <float.h>
#include <DataTypes.h>

DatabaseOperator::DatabaseOperator(void)
	:IDataStore()
{
	otl_connect::otl_initialize();
}


DatabaseOperator::~DatabaseOperator(void)
{
	Release();
}

int DatabaseOperator::Insert( void* pStruct )
{
	if (!m_bIsOK)
	{
		return 0;
	}
	return 1;
}

int DatabaseOperator::StoreBasetable( instrument_container & container )
{
	if (!m_bIsOK)
	{
		return 0;
	}
	container.lock();
	int iRet=-1;
	try{
		ostringstream sqlBuf;
		sqlBuf<<"create table if not exists instruments("
			<<"InstrumentID char(31),"
			<<"ExchangeID char(9),"
			<<"InstrumentName char(21),"
			<<"ExchangeInstID char(31),"
			<<"ProductID char(31),"
			<<"ProductClass int,"
			<<"DeliveryYear int,"
			<<"DeliveryMonth int,"
			<<"MaxMarketOrderVolume int,"
			<<"MinMarketOrderVolume int,"
			<<"MaxLimitOrderVolume int,"
			<<"MinLimitOrderVolume int,"
			<<"VolumeMultiple int,"
			<<"PriceTick double,"
			<<"CreateDate char(9),"
			<<"OpenDate char(9),"
			<<"ExpireDate char(9),"
			<<"StartDelivDate char(9),"
			<<"EndDelivDate char(9),"
			<<"InstLifePhase int,"
			<<"IsTrading int,"
			<<"PositionType int,"
			<<"PositionDateType int,"
			<<"LongMarginRatio double,"
			<<"ShortMarginRatio double,"
			<<"Primary Key(InstrumentID,ExchangeID)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
		db.direct_exec(sqlBuf.str().c_str());
		ostringstream sqlBuf2,valBuf;
		sqlBuf2<<"insert into instruments values("
			<<":f1<char[31]>,"
			<<":f2<char[9]>,"
			<<":f3<char[21]>,"
			<<":f4<char[31]>,"
			<<":f5<char[31]>,"
			<<":f6<int>,"
			<<":f7<int>,"
			<<":f8<int>,"
			<<":f9<int>,"
			<<":f10<int>,"
			<<":f11<int>,"
			<<":f12<int>,"
			<<":f13<int>,"
			<<":f14<double>,"
			<<":f15<char[9]>,"
			<<":f16<char[9]>,"
			<<":f17<char[9]>,"
			<<":f18<char[9]>,"
			<<":f19<char[9]>,"
			<<":f20<int>,"
			<<":f21<int>,"
			<<":f22<int>,"
			<<":f23<int>,"
			<<":f24<double>,"
			<<":f25<double>)";
		size_t i=0;
		for (i=0;i<container.size();i++)
		{
			instrument_info& info=container[i];
			string sql=string("select * from instruments where InstrumentID='")+info.get_id()+"'";
			otl_stream o_query(50,sql.c_str(),db);
			if (!o_query.eof())
			{
				continue;
			}
			otl_stream o(1,sqlBuf2.str().c_str(),db);//插入时，第一个参数为1，参见otl的文档
			if (strlen(info.ProductID)<=0)
			{
                strncpy(info.ProductID,info.szCode,31);
			}
			o<<info.szCode
			<<info.szExchange
			<<info.szName
			<<info.ExchangeInstID
			<<info.ProductID
			<<info.ProductClass
			<<info.DeliveryYear
			<<info.DeliveryMonth
			<<info.MaxMarketOrderVolume
			<<info.MinMarketOrderVolume
			<<info.MaxLimitOrderVolume
			<<info.MinLimitOrderVolume
			<<info.VolumeMultiple
			<<info.PriceTick
			<<info.CreateDate
			<<info.OpenDate
			<<info.ExpireDate
			<<info.StartDelivDate
			<<info.EndDelivDate
			<<info.InstLifePhase
			<<info.IsTrading
			<<info.PositionType
			<<info.PositionDateType
			<<info.LongMarginRatio
			<<info.ShortMarginRatio;
		}
		iRet=i;
	}catch(otl_exception& p){
		last_error_msg=(char*)p.msg;
		DEBUG_METHOD();
		DEBUG_PRINTF("DatabaseOperator::StoreBasetable发生错误:%s",p.msg);
		iRet=-1;
	}
	catch(std::exception& e)
	{
		last_error_msg=e.what();
		DEBUG_METHOD();
		DEBUG_PRINTF("DatabaseOperator::StoreBasetable发生错误:%s",e.what());
		iRet=-1;
	}
	catch(...)
	{
		DEBUG_METHOD();
		DEBUG_MESSAGE("DatabaseOperator::StoreBasetable发生错误:未知的异常...");
		iRet=-1;
	}
	container.unlock();
	return iRet;
}

int DatabaseOperator::StoreReport(Tick * pOnceData, int nCount, bool bBigTrade)
{
	if (!m_bIsOK)
	{ 
		return 0;
	}
	//为每个合约创建一个表
	for (int i=0;i<nCount;++i)
	{
		try{
			if (NULL==(pOnceData+i))
			{
				continue;
			}
			//表名=合约_交易日;
			DateTime data_day(pOnceData->UpdateTime);
			static string trade_day=data_day.FormatStd("%Y%m%d");
			string table_name=string(pOnceData[i].szCode)+"_"+trade_day;
			ostringstream sqlBuf;
			sqlBuf<<"create table if not exists "<<table_name<<"("
				<<"InstrumentID char(31),"
				<<"ExchangeID char(9),"
				<<"TradingTime int,"
				<<"TradingMillisec int,"
				<<"PreClosePrice double,"
				<<"OpenPrice double,"
				<<"ClosePrice double,"
				<<"HighestPrice double,"
				<<"LowestPrice double,"
				<<"LastPrice double,"
				<<"AveragePrice double,"
				<<"CurrDelta double,"
				<<"PreDelta double,"
				<<"PreSettlementPrice double,"
				<<"SettlementPrice double,"
				<<"UpperLimitPrice double,"
				<<"LowerLimitPrice double,"
				<<"OpenInterest double,"
				<<"Volume double,"
				<<"Turnover double,"
				<<"BidPrice1 double,"
				<<"BidPrice2 double,"
				<<"BidPrice3 double,"
				<<"BidVolume1 int,"
				<<"BidVolume2 int,"
				<<"BidVolume3 int,"
				<<"AskPrice1 double,"
				<<"AskPrice2 double,"
				<<"AskPrice3 double,"
				<<"AskVolume1 int,"
				<<"AskVolume2 int,"
				<<"AskVolume3 int)ENGINE=innoDB DEFAULT CHARSET=utf8";
			db.direct_exec(sqlBuf.str().c_str());
			ostringstream sqlBuf2;
			sqlBuf2<<"insert into "<<table_name<<" values("
				<<":f1<char[31]>,"
				<<":f2<char[9]>,"
				<<":f3<int>,"
				<<":f4<int>,"
				<<":f5<double>,"
				<<":f6<double>,"
				<<":f7<double>,"
				<<":f8<double>,"
				<<":f9<double>,"
				<<":f10<double>,"
				<<":f11<double>,"
				<<":f12<double>,"
				<<":f13<double>,"
				<<":f14<double>,"
				<<":f15<double>,"
				<<":f16<double>,"
				<<":f17<double>,"
				<<":f18<double>,"
				<<":f19<double>,"
				<<":f20<double>,"
				<<":f21<double>,"
				<<":f22<double>,"
				<<":f23<double>,"
				<<":f24<int>,"
				<<":f25<int>,"
				<<":f26<int>,"
				<<":f27<double>,"
				<<":f28<double>,"
				<<":f29<double>,"
				<<":f30<int>,"
				<<":f31<int>,"
				<<":f32<int>)";
			otl_stream o(1,sqlBuf2.str().c_str(),db);
			o<<pOnceData[i].szCode
				<<pOnceData[i].ExchangeID
				<<(int)pOnceData[i].UpdateTime
				<<pOnceData[i].UpdateMillisec
				<<pOnceData[i].PreClosePrice
				<<pOnceData[i].OpenPrice
				<<pOnceData[i].ClosePrice
				<<pOnceData[i].HighestPrice
				<<pOnceData[i].LowestPrice
				<<pOnceData[i].LastPrice
				<<pOnceData[i].AveragePrice
				<<pOnceData[i].CurrDelta
				<<pOnceData[i].PreDelta
				<<pOnceData[i].PreSettlementPrice
				<<pOnceData[i].SettlementPrice
				<<pOnceData[i].UpperLimitPrice
				<<pOnceData[i].LowerLimitPrice
				<<pOnceData[i].OpenInterest
				<<(long long)pOnceData[i].Volume
				<<pOnceData[i].Turnover
				<<pOnceData[i].BidPrice[0]
				<<pOnceData[i].BidPrice[1]
				<<pOnceData[i].BidPrice[2]
				<<pOnceData[i].BidVolume[0]
				<<pOnceData[i].BidVolume[1]
				<<pOnceData[i].BidVolume[2]
				<<pOnceData[i].AskPrice[0]
				<<pOnceData[i].AskPrice[1]
				<<pOnceData[i].AskPrice[2]
				<<pOnceData[i].AskVolume[0]
				<<pOnceData[i].AskVolume[1]
				<<pOnceData[i].AskVolume[2];
		}catch(otl_exception& p){
			last_error_msg=(char*)p.msg;
			DEBUG_METHOD();
			DEBUG_PRINTF("DatabaseOperator::StoreReport错误:%s",p.msg);
		}
	}
	return 1;
}

int DatabaseOperator::StoreMinute( MINUTE * pMultipleData, int nCount )
{
	if (!m_bIsOK)
	{
		return 0;
	}
	try{
	ostringstream sqlBuf1;
	sqlBuf1<<"create table if not exists "<<pMultipleData->szCode<<"("
		<<"InstrumentID char(31),"
		<<"LastPrice double,"
		<<"HighestPrice double,"
		<<"LowestPrice double,"
		<<"Volume int,"
		<<"Turnover double,"
		<<"UpdateTime char(9),"
		<<"UpdateMillisec int) ENGINE=InnoDB DEFAULT CHARSET=utf8";
	db.direct_exec(sqlBuf1.str().c_str());
	ostringstream sqlBuf2;
	sqlBuf2<<"insert into "<<pMultipleData->szCode<<" values("
		<<":f1<char[31]>,"
		<<":f2<double>,"
		<<":f3<double>,"
		<<":f4<double>,"
		<<":f5<int>,"
		<<":f6<double>,"
		<<":f7<char[9]>,"
		<<":f8<int>)";
	otl_stream o(1,sqlBuf2.str().c_str(),db);
	DateTime time(pMultipleData->TradingTime);
	string timeStr=time.FormatStd("%H:%M:%S");
		o<<pMultipleData->szCode
		<<pMultipleData->LastPrice 
		<<pMultipleData->HighestPrice
		<<pMultipleData->LowestPrice
		<<(long long)pMultipleData->Volume   
		<<pMultipleData->Turnover
		<<(timeStr.c_str())
		<<pMultipleData->TradingMillisec;
	}catch(otl_exception& p){
		last_error_msg=(char*)p.msg;
		return -1;
	}
	return 1;
}

//connect执行登录，只需要调用一次
int DatabaseOperator::Init(const string& initStr )
{
	if (m_bIsOK)
	{
		return 0;
	}
	try
	{
		rlogon(initStr.c_str());
		m_bIsOK=true;
		return 1;
	}
	catch (otl_exception& p)
	{
		DEBUG_METHOD();
		DEBUG_PRINTF("数据库发生异常:%s",p.msg);
		last_error_msg=(char*)p.msg;
		m_bIsOK=false;
		return -1;
	}
}

//登录
void DatabaseOperator::rlogon( string logonStr )
{
	try
	{
		db.rlogon(logonStr.c_str(),0);
/*		otl_cursor::direct_exec(db,"set names UTF-8");*/
		otl_cursor::direct_exec(db,"use ctptest");
		strcpy(m_szRootPath,logonStr.c_str());
		m_bIsOK=true;
	}
	catch (otl_exception& p)
	{
		last_error_msg=(char*)(p.msg);
		DEBUG_METHOD();
		DEBUG_PRINTF("数据库登录发生异常:%s",p.msg);
		m_bIsOK=false;
	}
	catch(std::exception& ex)
	{
		DEBUG_METHOD();
        DEBUG_PRINTF("数据库登录发生异常:%s",ex.what());
		m_bIsOK=false;
	}
}

int DatabaseOperator::Release()
{
	DEBUG_METHOD();
	if (!m_bIsOK)
	{
		return 0;
	}
	try
	{
		db.logoff();
		m_bIsOK=false;
	}catch(otl_exception& p)
	{
		last_error_msg=(char*)(p.msg);
		DEBUG_PRINTF("DatabaseOperator::Release异常:%s",p.msg);
		return -1;
	}
	return 1;
}

int DatabaseOperator::IsDataSetExists( string tableName )
{
	DEBUG_METHOD();
	if (!m_bIsOK)
	{
		return 0;
	}
	try{
		string sql=
			"select `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` where `TABLE_SCHEMA`='";
		sql+=GetRootDataSetName();
		sql+"' and `TABLE_NAME`='";
		sql+=tableName;
		sql+="'";
		otl_stream o(50,sql.c_str(),db);
		char tableNames[32];
		while(!o.eof())
		{
			o>>tableNames;
			return 1;
		}
		return 0;
	}catch (otl_exception& p)
	{
		last_error_msg=(char*)(p.msg);
		DEBUG_PRINTF("DatabaseOperator::IsDataSetExists异常:%s",p.msg);
		return -1;
	}
	return 0;
}


int DatabaseOperator::SetOptions( int optionType,int optionValue )
{

	return 0;
}
//注意，是取得所有的字段名称
vector<string> DatabaseOperator::GetDataSetFieldNames( string setName )
{
	vector<string> fieldNames;
	char fieldName[32];
	try{
		string sql="SELECT column_name FROM information_schema.columns WHERE table_name like'";
		sql+=setName;
		sql+="'";
		otl_stream o(50,sql.c_str(),db);
		while (!o.eof())
		{
			o>>fieldName;
			fieldNames.push_back(fieldName);
		}
	}catch(otl_exception& p)
	{
		last_error_msg=(char*)p.msg;
	}
	return fieldNames;
}

//void DatabaseOperator::GetInstrumentInfo( CInstrumentInfo* pInfo,const char* szID )
//{
//	pInfo->SetInstrumentID("shez","CF1201");
//	pInfo->SetInstrumentName("合约1");
//	pInfo->SetExchangeID("shez");
//	/*
//	memcpy(pInfo->InstrumentID,si.InstrumentID,sizeof(InstrumentID));
//	memcpy(InstrumentName,si.InstrumentName,sizeof(InstrumentName));
//	memcpy(ExchangeID,si.ExchangeID,sizeof(ExchangeID));
//	memcpy(ExchangeInstID,si.ExchangeInstID,sizeof(ExchangeInstID));
//	memcpy(ProductID,si.ProductID,sizeof(ProductID));
//	ProductClass=si.ProductClass;
//	DeliveryYear=si.DeliveryYear;
//	DeliveryMonth=si.DeliveryMonth;
//	MaxMarketOrderVolume=si.MaxMarketOrderVolume;
//	MinMarketOrderVolume=si.MinMarketOrderVolume;
//	MinLimitOrderVolume=si.MinLimitOrderVolume;
//	MaxLimitOrderVolume=si.MaxLimitOrderVolume;
//	VolumeMultiple=si.VolumeMultiple;
//	PriceTick=si.PriceTick;
//	memcpy(CreateDate,si.CreateDate,sizeof(CreateDate));
//	memcpy(OpenDate,si.OpenDate,sizeof(OpenDate));
//	memcpy(ExpireDate,si.ExpireDate,sizeof(ExpireDate));
//	memcpy(StartDelivDate,si.StartDelivDate,sizeof(StartDelivDate));
//	memcpy(EndDelivDate,si.EndDelivDate,sizeof(EndDelivDate));
//	InstLifePhase=si.InstLifePhase;
//	IsTrading=si.IsTrading;
//	PositionType=si.PositionType;
//	LongMarginRatio=si.LongMarginRatio;
//	ShortMarginRatio=si.ShortMarginRatio;
//	memcpy(TradingDay,si.TradingDay,sizeof(TradingDay));
//	PreSettlementPrice=si.PreSettlementPrice;
//	SettlementPrice=si.SettlementPrice;
//	PreClosePrice=si.PreClosePrice;
//	PreOpenInterest=si.PreOpenInterest;
//	OpenPrice=si.OpenPrice;
//	HighestPrice=si.HighestPrice;
//	LowestPrice=si.LowestPrice;
//	OpenInterest=si.OpenInterest;
//	ClosePrice=si.ClosePrice;
//	PreDelta=si.PreDelta;
//	CurrDelta=si.CurrDelta;
//	AveragePrice=si.AveragePrice;
//	LastPrice=si.LastPrice;
//	Volume=Volume;
//	Turnover=Turnover;
//	UpperLimitPrice=UpperLimitPrice;
//	LowerLimitPrice=LowerLimitPrice;
//	memcpy(UpdateTime,si.UpdateTime,sizeof(UpdateTime));
//
//	UpdateMillisec=si.UpdateMillisec;
//	*/
//}

//pInstrument至少应当包含合约代码
//这里先做以天为周期的情况

//通过SQL语句来控制获取的K线数据
int DatabaseOperator::LoadKData( instrument* pInstrument,int nKType )
{
	//将原来的数据清空
	DEBUG_METHOD();
	pInstrument->GetKDataDay().Clear();
	switch (nKType)
	{
	case ktypeDay:
		try{
			KDATA tempKData;
			DateTime currTime=DateTime::GetTradingDay();
			DateTime kDataTime=currTime;
			int query_table_times=0;
			do 
			{
				char tableName[32]={0};
				//构建表名;
				sprintf(tableName,"%s_%04d%02d%02d",pInstrument->GetInstrumentID(),kDataTime.GetYear(),
					kDataTime.GetMonth(),kDataTime.GetDay());
				string sql="select InstrumentID, FROM_UNIXTIME(TradingTime,'%Y%m%d') TradingDay,min(LastPrice), "
					"max(LastPrice),open_table.OpenPrice,close_table.ClosePrice,avg(LastPrice),avg(PreSettlementPrice),"
					"avg(PreClosePrice),avg(OpenInterest),sum(Volume),sum(Turnover) from "
					+string(tableName)+
					",(select LastPrice OpenPrice from "
					+string(tableName)+
					" where TradingTime=(select min(TradingTime) from "
					+string(tableName)+
					")) open_table,(select LastPrice ClosePrice from "
					+string(tableName)+
					" where TradingTime =(select max(TradingTime) from "
					+string(tableName)+
					")) close_table";
				DEBUG_PRINTF("查询K线数据:%s",sql.c_str());
				try{
//					otl_stream o(1024,sql.c_str(),db);
// 					while (!o.eof())
// 					{
// 						o>>tempKData.szCode
// 							>>tempKData.TradingDay
// 							>>tempKData.LowestPrice
// 							>>tempKData.HighestPrice
// 							>>tempKData.OpenPrice
// 							>>tempKData.ClosePrice
// 							>>tempKData.AveragePrice
// 							>>tempKData.PreSettlementPrice
// 							>>tempKData.PreClosePrice
// 							>>tempKData.OpenInterest
// 							>>tempKData.PreOpenInterest
// 							>>tempKData.Volume
// 							>>tempKData.Turnover;
// 						tempKData.Reserved=0;
// 						tempKData.TradingDate=atoi(tempKData.TradingDay);
// 						pInstrument->GetKDataDay().add(tempKData);
// 					}
				}
				catch(otl_exception& p)
				{
					DEBUG_PRINTF("LoadKData day:%s",p.msg);
					DEBUG_PRINTF("LoadKData day:%s",p.sqlstate);
					DEBUG_PRINTF("LoadKData day:%s",p.stm_text);
					DEBUG_PRINTF("LoadKData day:%s",p.var_info);
				}
				if (pInstrument->GetKDataDay().size()>100)
				{
					break;
				}
				++query_table_times;
				//时间向前推一天;
				kDataTime-=TimeSpan(1,0,0,0);
			} while (query_table_times<1000);
		}catch(otl_exception& p){ // intercept OTL exceptions  
            DEBUG_METHOD();
            DEBUG_PRINTF("LoadKData:%s",p.msg);
            DEBUG_PRINTF("LoadKData:%s",p.sqlstate);
            DEBUG_PRINTF("LoadKData:%s",p.stm_text);
            DEBUG_PRINTF("LoadKData:%s",p.var_info);
		}
		catch(std::exception& ex)
		{
            DEBUG_METHOD();
            DEBUG_PRINTF("LoadKData:%s",ex.what());
		}
		break;
	case ktypeMin5:
		try
		{
			//查分钟数据表;

			KDATA tempKData;
			DateTime currTime=DateTime::GetTradingDay();

			TimeSpan minuteDelta(0,0,nKType,0);
			//方法1，利用程序进行处理:取出5分钟内的Tick数据，然后进行筛选;
			if(true)
			{
				int query_table_times=0;
				//1.今天的开盘时间;
				DateTime dayOpenTime;
				if (currTime.GetHour()<9)
				{
					//夜盘,开盘时间为前一天的21;
					dayOpenTime=
						DateTime(currTime.GetYear(),currTime.GetMonth(),currTime.GetDay(),21,0,0) 
						- TimeSpan(1,0,0,0);
				}
				else
				{
					dayOpenTime=DateTime(currTime.GetYear(),currTime.GetMonth(),currTime.GetDay(),9,0,0);
				}

// 				if (preMinuteTime>dayOpenTime+time_span(0,6,30,0))
// 				{
// 					//当前时间大于收盘时间;
// 					preMinuteTime=(dayOpenTime+time_span(0,6,30,0));
// 				}
				std::string table_name=std::string(pInstrument->GetInstrumentID())+"_"+currTime.FormatStd("%Y%m%d");
				//1.取列表中的最大时间;
				std::string sql_select_max_time="select max(TradingTime) from "+table_name;
				otl_stream o_max_time(1024,sql_select_max_time.c_str(),db);
				//默认为收盘时间;
				long cur_max_time=(dayOpenTime+TimeSpan(0,6,30,0)).GetTime();
				try
				{
					if (!o_max_time.eof())
					{
						o_max_time>>cur_max_time;
					}
				}
				catch (otl_exception& p)
				{
					last_error_msg=(char*)p.msg;
				}
				
				DateTime preMinuteTime(cur_max_time);
				std::string str_pre_minute_time1 =preMinuteTime.FormatStd("%Y%m%d %H:%M:%S");
				do 
				{
					if (preMinuteTime<dayOpenTime)
					{
						//当前还没有开盘,则跳转到昨天的收盘时间;
						//从今天的开盘时间到昨天的收盘时间是17小时30分;
						preMinuteTime=dayOpenTime-TimeSpan(0,17,30,0);
						//往前推一天;
						dayOpenTime=dayOpenTime-TimeSpan(0,24,0,0);
						//构造表名;
						table_name=std::string(pInstrument->GetInstrumentID())+"_"+preMinuteTime.FormatStd("%Y%m%d");
					}

					//取出5分钟内的数据;
					ostringstream sql;
					sql<<"select InstrumentID,ExchangeID,FROM_UNIXTIME(Tradingtime,'%Y%m%d') TradingDay,Tradingtime,"
						"LastPrice,PreSettlementPrice,"
						"PreClosePrice,OpenInterest,Volume,Turnover from "<<(table_name)<<
						" where TradingTime <="<<preMinuteTime.GetTime()<<" and TradingTime >="
						<<(preMinuteTime-minuteDelta).GetTime();



					DEBUG_PRINTF("LoadKData:%d-%d-%d %02d:%02d:%02d",preMinuteTime.GetYear(),
						preMinuteTime.GetMonth(),preMinuteTime.GetDay(),preMinuteTime.GetHour(),
						preMinuteTime.GetMinute(),preMinuteTime.GetSecond());
					try{
						//提取一条K线数据;
						std::string sql_str=sql.str().c_str();
						//otl_stream o(10240,sql_str.c_str(),db);
						double ClosePrice=0,Turnover=0,OpenPrice=0,HighestPrice=0,LowestPrice=DBL_MAX;
						long TradingTime=0,Volume=0;
						bool hasData=false;
//						for (int i=0;!o.eof();i++)
						{
// 							o>>tempKData.szCode
// 								>>tempKData.szExchange
// 								>>tempKData.TradingDay
// 								>>TradingTime
// 								>>ClosePrice
// 								>>tempKData.PreSettlementPrice
// 								>>tempKData.PreClosePrice
// 								>>tempKData.OpenInterest
// 								>>tempKData.Volume
// 								>>tempKData.Turnover;
							if (HighestPrice<ClosePrice)
							{
								HighestPrice=ClosePrice;
							}
							if (LowestPrice>ClosePrice)
							{
								LowestPrice=ClosePrice;
							}
							Volume+=tempKData.Volume;
							Turnover+=tempKData.Turnover;
// 							if (i==0)
// 							{
// 								//开盘;
// 								OpenPrice=ClosePrice;
// 							}
							hasData=true;
						}
						if (hasData)
						{
							tempKData.OpenPrice=OpenPrice;
							tempKData.ClosePrice=ClosePrice;
							tempKData.HighestPrice=HighestPrice;
							tempKData.LowestPrice=LowestPrice;
							tempKData.Volume=Volume;
							tempKData.Turnover=Turnover;
							tempKData.TradingTime=preMinuteTime.GetTime();
							
							DateTime tt(tempKData.TradingTime);
							char strDate[8]={0},strTime[8]={0};
							sprintf(strDate,"%2d%02d%02d",tt.GetYear()-1990,tt.GetMonth(),tt.GetDay());
							sprintf(strTime,"%02d%02d",tt.GetHour(),tt.GetMinute());
							int tTime=atoi(strTime);
							int tDate=atoi(strDate);
							int tDosDate =tDate*10000+tTime;
							tempKData.TradingDate = tDosDate;
							pInstrument->GetKDataMin5().InsertKDataSort(tempKData);
						}
						if (pInstrument->GetKDataMin5().size()>=100)
						{
							//最多取1000条数据;
							break;
						}
					}
					catch(otl_exception& p)
					{
						DEBUG_PRINTF("LoadKData 5min:%s",p.msg);
						DEBUG_PRINTF("LoadKData 5min:%s",p.sqlstate);
						DEBUG_PRINTF("LoadKData 5min:%s",p.stm_text);
						DEBUG_PRINTF("LoadKData 5min:%s",p.var_info);
					}
					query_table_times++;
					//时间往前推5分钟;
					preMinuteTime-=minuteDelta;
				} while (query_table_times<=1000);
			}
			else
			//方法2，使用SQL语句直接获取K线数据;
			{
				//取出开盘时间和收盘时间;
// 				ostringstream sql;
// 				sql<<"select min(TradingTime) OpenTime,max(TradingTime) CloseTime from "<<(table_name)<<
// 					" where TradingTime <="<<preMinuteTime.GetTime()<<" and TradingTime >="<<preMinuteTime-secondDelta;
// 				//取出开盘价，收盘价，最高价，最低价，成交量总全，成交额总和;
// 				sql<<"SELECT LastPrice,MAX(LastPrice) AS HighestPrice,MIN(LastPrice) AS LowestPrice,Volume,Turnover,UpdateTime,UpdateMillisec FROM M"
// 					<<" WHERE InstrumentID='"<<pInstrument->GetInstrumentID()<<"' GROUP BY UpdateTime,UpdateMillisec";
// 				select InstrumentID,FROM_UNIXTIME(max(Tradingtime),'%Y%m%d') TradingDay,
// 					min(LastPrice),max(LastPrice),avg(LastPrice) AveragePrice,
// 					sum(Volume) V,sum(Turnover),TradingTime CloseTime from 
// 					(select * from if1406_20140530 where TradingTime<=1401418798 and TradingTime>=(1401418798-300) ) SubDataTable
// 					having CloseTime=1401418798
// 				otl_stream o(1024,sql.str().c_str(),db);
// 				//AfxGetLog()->StatusOut("sql=%s",o.get_stm_text());
// 				while (!o.eof())
// 				{
// 					o>>tempKData.InstrumentID
// 						>>tempKData.TradingDay
// 						>>tempKData.OpenPrice
// 						>>tempKData.HighestPrice
// 						>>tempKData.LowestPrice
// 						>>tempKData.ClosePrice
// 						>>tempKData.AveragePrice
// 						>>tempKData.PreSettlementPrice
// 						>>tempKData.PreClosePrice
// 						>>tempKData.OpenInterest
// 						>>tempKData.PreOpenInterest;
// 					//这些数据也要查
// 					tempKData.Volume=tempKData.OpenInterest;
// 					tempKData.Turnover=tempKData.HighestPrice;
// 					tempKData.Reserved=0;
// 					tempKData.TradingDate=atoi(tempKData.TradingDay);
// 					pInstrument->GetKDataDay().Add(tempKData);
// 				}
			}
		}
		catch (otl_exception& p)
		{
			last_error_msg=(char*)p.msg;
		}
	}

	return 1;
}

//从合约表中查询合约的基本信息
//还要从其他表中查询合约的其他信息
int DatabaseOperator::LoadBaseText( instrument* pInstrument )
{
	if (!m_bIsOK)
	{
		return 0;
	}
	try{
		BASEDATA tempBasic/*={0}*/;
		string id=pInstrument->GetInstrumentID();
		string sql="SELECT InstrumentID,InstrumentName,Instruments.ExchangeID,ExchangeInstID,ExchangeName,ExchangeProperty,"
			"ProductID,ProductClass,DeliveryYear,DeliveryMonth,MaxMarketOrderVolume,MinMarketOrderVolume,MaxLimitOrderVolume,"
			"MinLimitOrderVolume,VolumeMultiple,PriceTick,CreateDate,OpenDate,ExpireDate,StartDelivDate,EndDelivDate,"
			"InstLifePhase,IsTrading,PositionType,PositionDateType,LongMarginRatio,ShortMarginRatio FROM Instruments,"
			"Exchanges WHERE Instruments.ExchangeID=Exchanges.ExchangeID AND InstrumentID='";
		sql+=pInstrument->GetInstrumentID();
		sql+="'";
		otl_stream o(256,sql.c_str(),db);
		while (!o.eof())
		{
			o>>tempBasic.szCode
				>>tempBasic.szName
				>>tempBasic.szExchange
				>>tempBasic.ExchangeInstID
				>>tempBasic.ExchangeName
				>>tempBasic.ExchangeProperty
				>>tempBasic.ProductID
				>>tempBasic.ProductClass
				>>tempBasic.DeliveryYear
				>>tempBasic.DeliveryMonth
				>>tempBasic.MaxMarketOrderVolume
				>>tempBasic.MinMarketOrderVolume
				>>tempBasic.MaxLimitOrderVolume
				>>tempBasic.MinLimitOrderVolume
				>>tempBasic.VolumeMultiple
				>>tempBasic.PriceTick
				>>tempBasic.CreateDate
				>>tempBasic.OpenDate
				>>tempBasic.ExpireDate
				>>tempBasic.StartDelivDate
				>>tempBasic.EndDelivDate
				>>tempBasic.InstLifePhase
				>>tempBasic.IsTrading
				>>tempBasic.PositionType
				>>tempBasic.PositionDateType
				>>tempBasic.LongMarginRatio
				>>tempBasic.ShortMarginRatio;
		}
	}catch(otl_exception& p){ 
		last_error_msg=(char*)p.msg;
		return -1;
	}
	return 1;
}
/**
 * \brief 获取分时行情数据
 *
 */
int DatabaseOperator::LoadMinute( instrument* pInstrument )
{
	if (!m_bIsOK)
	{
		return 0;
	}
	try{
		DateTime currTime=DateTime::current_time();//由pInstrument传一个时间过来
		ostringstream tableName;
		tableName<<pInstrument->GetInstrumentID()<<"_"<<pInstrument->GetInstrumentInfo().TradingDay;


		MINUTE tempMinute;
		ostringstream sql;//
		//最新价:一分钟里的最后一个tick数据;

		sql<<"select LastPrice,min(src_table.LastPrice) as lowest_price,max(src_table.LastPrice) as highest_price,src_table.Volume,"
		"src_table.Turnover,FROM_UNIXTIME(TradingTime,'%Y-%M-%D %h:%i:%s') as minuteTime0 ,src_table.TradingMillisec ,src_table.TradingTime"
		" from "<<tableName.str()<<" src_table,((select FROM_UNIXTIME(TradingTime,'%Y-%M-%D %h:%i:%s') minuteTime1 from "
		<<tableName.str()<<" group by FROM_UNIXTIME(TradingTime,'%Y-%M-%D %h:%i')) dest_table)  where "
		" FROM_UNIXTIME(src_table.TradingTime,'%Y-%M-%D %h:%i:%s')=dest_table.minuteTime1 group by minuteTime0 Order by TradingTime";
		std::string sql1=sql.str();
		char UpdateTime[64]={0};
		otl_stream o(64,sql.str().c_str(),db);
		long tradingTime=0;
		while (!o.eof())
		{
			o>>tempMinute.LastPrice
  				>>tempMinute.HighestPrice
  				>>tempMinute.LowestPrice
				>>(long long)tempMinute.Volume
				>>tempMinute.Turnover
				>>UpdateTime
				>>tempMinute.TradingMillisec
				>>tradingTime;
			tempMinute.TradingTime=tradingTime/*ConvertTime2Seconds(tableName.str(),string(UpdateTime))*/;
			pInstrument->GetMinute().add(tempMinute);
		}
	}catch(otl_exception& p){
		last_error_msg=(char*)p.msg;
	}
	return 1;
}
/**
 * \brief 取得分时行情的详细数据
 *
 */
int DatabaseOperator::LoadReport( instrument* pInstrument )
{
	if (!m_bIsOK)
	{
		return 0;
	}
 	try{
		DateTime currTime=DateTime::current_time();//由pInstrument传一个时间过来;
		string tname(pInstrument->GetInstrumentID()+string("_"));
		if (string(pInstrument->GetInstrumentInfo().TradingDay).empty())
		{
			tname+=currTime.FormatStd("%Y%m%d");

		}
		else
		{
			tname+=pInstrument->GetInstrumentInfo().TradingDay;
		}

		 ostringstream sql;
		 sql<<"SELECT InstrumentID,ExchangeID,TradingMillisec,PreClosePrice,"
			 "OpenPrice,ClosePrice,HighestPrice,LowestPrice,LastPrice,AveragePrice,CurrDelta,PreDelta,"
			 "PreSettlementPrice,SettlementPrice,UpperLimitPrice,LowerLimitPrice,OpenInterest,"
			 "Volume,Turnover,BidPrice1,BidVolume1,AskPrice1,AskVolume1,BidPrice2,BidVolume2,"
			 "AskPrice2,AskVolume2,BidPrice3,BidVolume3,AskPrice3,AskVolume3,TradingTime FROM "
			 <<tname<<" where TradingTime < "<<pInstrument->m_rptTimeEnd.GetTime()
			 <<" and TradingTime > "<<pInstrument->m_rptTimeBegin.GetTime();
		 string sql1=sql.str();
		otl_stream o(10240,sql1.c_str(),db);
		Tick tempReport;
		while (!o.eof())
		{
			int trade_time=0;
			o>>tempReport.szCode
				>>tempReport.ExchangeID
				>>(tempReport.UpdateMillisec)
				>>tempReport.PreClosePrice
				>>tempReport.OpenPrice
				>>tempReport.ClosePrice
				>>tempReport.HighestPrice
				>>tempReport.LowestPrice
				>>tempReport.LastPrice
				>>tempReport.AveragePrice
				>>tempReport.CurrDelta
				>>tempReport.PreDelta
				>>tempReport.PreSettlementPrice
				>>tempReport.SettlementPrice
				>>tempReport.UpperLimitPrice
				>>tempReport.LowerLimitPrice
				>>tempReport.OpenInterest
				>>tempReport.Volume
				>>tempReport.Turnover
				>>tempReport.BidPrice[0]
				>>tempReport.BidVolume[0]
				>>tempReport.AskPrice[0]
				>>tempReport.AskVolume[0]
				>>tempReport.BidPrice[1]
				>>tempReport.BidVolume[1]
				>>tempReport.AskPrice[1]
				>>tempReport.AskVolume[1]
				>>tempReport.BidPrice[2]
				>>tempReport.BidVolume[2]
				>>tempReport.AskPrice[2]
				>>tempReport.AskVolume[2]
				>>trade_time;
				tempReport.UpdateTime=trade_time;
			pInstrument->GetReport().InsertReportSort(tempReport);
		}
	}catch(otl_exception& p){
		last_error_msg=(char*)p.msg;
		return -1;
	}
	return 1;
}



//将时分秒转换为秒
//hh:mm:ss时间
//YYYYMMDD日期
long DatabaseOperator::ConvertTime2Seconds(string strDay, string strTime )
{
//	ASSERT(strTime.size()==8);
//	ASSERT(strDay.size()==8);
	char hour[4];
	char minute[4];
	char second[4];
	char YYYY[6];
	char MM[4];
	char DD[4];
    strncpy(YYYY,strDay.c_str(),4);
    strncpy(MM,strDay.c_str()+4,2);
    strncpy(DD,strDay.c_str()+6,2);

    strncpy(hour,strTime.c_str(),2);
    strncpy(minute,strTime.c_str()+3,2);
    strncpy(second,strTime.c_str()+6,2);

	struct tm s_tm={0};
	s_tm.tm_year=atoi(YYYY)-1900;
	s_tm.tm_mon=atoi(MM)-1;
	s_tm.tm_mday=atoi(DD);

	s_tm.tm_hour=atoi(hour);
	s_tm.tm_min=atoi(minute);
	s_tm.tm_sec=atoi(second);
	DateTime t(atoi(YYYY),atoi(MM),atoi(DD),atoi(hour),atoi(minute),atoi(second));
	return t.GetTime();
}

int DatabaseOperator::LoadBasetable( instrument_container& container )
{
	if (!m_bIsOK)
	{
		return 0;
	}
	container.resize(0,256*4);
	try{
		BASEDATA tempBasic/*={0}*/;
		string sql="select * from Instruments";
		otl_stream o(50,sql.c_str(),db);
		
		while (!o.eof())
		{
			instrument_info info;
			o>>tempBasic.szCode
				>>tempBasic.szExchange
				>>tempBasic.szName
				>>tempBasic.ExchangeInstID
				>>tempBasic.ProductID
				>>tempBasic.ProductClass
				>>tempBasic.DeliveryYear
				>>tempBasic.DeliveryMonth
				>>tempBasic.MaxMarketOrderVolume
				>>tempBasic.MinMarketOrderVolume
				>>tempBasic.MaxLimitOrderVolume
				>>tempBasic.MinLimitOrderVolume
				>>tempBasic.VolumeMultiple
				>>tempBasic.PriceTick
				>>tempBasic.CreateDate
				>>tempBasic.OpenDate
				>>tempBasic.ExpireDate
				>>tempBasic.StartDelivDate
				>>tempBasic.EndDelivDate
				>>tempBasic.InstLifePhase
				>>tempBasic.IsTrading
				>>tempBasic.PositionType
				>>tempBasic.PositionDateType
				>>tempBasic.LongMarginRatio
				>>tempBasic.ShortMarginRatio;
			info.set_id(tempBasic.szExchange,tempBasic.szCode);
			instrument_info::update(info,&tempBasic);
			if (info.is_valid())
			{
				container.add(info);
			}
		}
	}catch(otl_exception& p){
		last_error_msg=(char*)p.msg;
	}
	return container.size();
}
/**
 * \brief 取得根据数集的名称
 * \remark 这个函数使用了ODBCAPI
 */
string DatabaseOperator::GetRootDataSetName()
{
	try{
		char dbName[32];
		SQLSMALLINT dbleng=0;
		SQLGetInfo(db.get_connect_struct().get_hdbc(),SQL_DATABASE_NAME,(SQLPOINTER)dbName,32,&dbleng);
		dbName[dbleng]=0;
		return string(dbName);
	}catch(otl_exception& p)
	{
		last_error_msg=(char*)p.msg;
		return "";
	}
	return "";
}

int DatabaseOperator::InstallNewsText( const char * buffer, int nLen, const char *orgname )
{
	return 0;
}

int DatabaseOperator::InstallNewsText( const char * filename, const char *orgname )
{
	return 0;
}


int DatabaseOperator::InstallBaseText( const char * buffer, int nLen, const char *orgname )
{
	return 0;
}

int DatabaseOperator::InstallBaseText( const char * filename, const char *orgname )
{
	return 0;
}


int DatabaseOperator::InstallBasetableFxj( const char * filename )
{
	return 0;
}

int DatabaseOperator::InstallBasetableTdx( const char * filename )
{
	return 0;
}

int DatabaseOperator::InstallBasetable( const char * filename, const char *orgname )
{
	return 0;
}

int DatabaseOperator::InstallDRDataFxj( const char * fxjfilename )
{
	return 0;
}

int DatabaseOperator::InstallDRDataClk( const char * filename, const char *orgname )
{
	return 0;
}

// int DatabaseOperator::InstallDRData( CDRData & drdata )
// {
// 	return 0;
// }

int DatabaseOperator::InstallKDataFxj( const char * dadfile, int nKType, PROGRESS_CALLBACK fnCallback, void *cookie )
{
	return 0;
}

int DatabaseOperator::InstallKDataTy( const char * stkfile, int nKType, PROGRESS_CALLBACK fnCallback, void *cookie )
{
	return 0;
}

int DatabaseOperator::InstallKData( kdata_container & kdata, bool bOverwrite /*= FALSE */ )
{
	if (!m_bIsOK)
	{
		return 0;
	}
	try
	{
		switch(kdata.GetKType())
		{
		case ktypeMin5:
			{
				ostringstream sqlBuf1;
				sqlBuf1<<"create table if not exists kdmin5("
					<<"InstrumentID char(31),"
					<<"ExchangeID char(31),"
					<<"TradingDay char(9),"
					<<"OpenPrice double,"
					<<"HighestPrice double,"
					<<"LowestPrice double,"
					<<"ClosePrice double,"
					<<"Volume int,"
					<<"Turnover double,"
					<<"AveragePrice double,"
					<<"PreClosePrice double,"
					<<"TradingTime int,"
					<<"Primary Key(InstrumentID,ExchangeID,TradingTime)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
				db.direct_exec(sqlBuf1.str().c_str());
				for (size_t i=0;i<kdata.size();i++)
				{
					KDATA kd=kdata.at(i);
					ostringstream sqlBuf2;
					sqlBuf2<<"insert into kdmin5 values("
						<<":f1<char[31]>,"
						<<":f2<char[31]>,"
						<<":f3<char[9]>,"
						<<":f4<double>,"
						<<":f5<double>,"
						<<":f6<double>,"
						<<":f7<double>,"
						<<":f8<int>,"
						<<":f9<double>,"
						<<":f10<double>,"
						<<":f11<double>,"
						<<":f12<int>)";
// 					otl_stream o(1,sqlBuf2.str().c_str(),db);
// 					ctp_time time(kd.TradingTime);
// 					string timeStr=time.FormatStd("%H:%M:%S");
// 					o<<kd.szCode
// 						<<kd.szExchange
// 						<<kd.TradingDay
// 						<<kd.OpenPrice
// 						<<kd.HighestPrice
// 						<<kd.LowestPrice
// 						<<kd.ClosePrice
// 						<<kd.Volume   
// 						<<kd.Turnover
// 						<<kd.AveragePrice
// 						<<kd.PreClosePrice
// 						<<(int)kd.TradingTime;
				}
			}
			break;
		case ktypeDay:
			{

			}
			break;

		}
		return kdata.size();
	}
	catch (otl_exception& e)
	{
		last_error_msg=(char*)e.msg;
		return -1;
	}
	return 0;
}

int DatabaseOperator::InstallCodetblFxjBlock( const char * filename, const char *orgname )
{
	return 0;
}

int DatabaseOperator::InstallCodetblBlock( const char * filename, const char *orgname )
{
	return 0;
}

int DatabaseOperator::InstallCodetbl( const char * filename, const char *orgname )
{
	return 0;
}

int DatabaseOperator::StoreOutline( OUTLINE * pOutline, int nCount )
{
	return 0;
}

int DatabaseOperator::LoadOutline( instrument *pstock )
{
	return 0;
}

int DatabaseOperator::StoreDRData( instrument *pstock )
{
	return 0;
}

int DatabaseOperator::LoadDRData( instrument *pstock )
{
	return 0;
}

int DatabaseOperator::LoadKDataCache( instrument_container &container, PROGRESS_CALLBACK fnCallback, void *cookie, int nProgStart, int nProgEnd )
{
	return 0;
}

int DatabaseOperator::StoreCodetable( instrument_container & container )
{
	return StoreBasetable(container);
}

int DatabaseOperator::GetMaxNumber()
{
	return 0;
}

bool DatabaseOperator::GetLastErrorMessage( char* lpszError, UINT nMaxError )
{
	//ASSERT(lpszError==NULL);
	if (NULL==lpszError)
	{
		return false;
	}
    strncpy(lpszError,last_error_msg.c_str(),nMaxError);
	return true;
}

DWORD DatabaseOperator::GetSelfTempPath( char *szTempPath, int size )
{
	return 0;
}

int DatabaseOperator::LoadCodetable( instrument_container &container )
{
	return 0;
}

int DatabaseOperator::GetDBTypeInfo(string& dbtypeName/* =string */)
{
	dbtypeName="OTL,ODBC,MYSQL";
	return IDataStore::dbtypeODBC;
}

bool DatabaseOperator::GetFileName( string &sFileName, int nDataType, instrument_info * pInfo /*= NULL*/, int nKType /*= ktypeDay */ )
{
	return false;

}

int DatabaseOperator::StoreKData( kdata_container & kdata, bool bOverwrite /*= false */ )
{
	return InstallKData(kdata,bOverwrite);
}

int DatabaseOperator::StoreExchange( vector<EXCHANGE>& exchanges )
{
	if (!m_bIsOK)
	{
		return 0;
	}
	int iRet=-1;
	try{
		ostringstream sqlBuf;
		sqlBuf<<"create table if not exists exchanges("
			<<"ExchangeID char(16),"
			<<"ExchangeName char(32),"
			<<"ExchangeProperty int,"
			<<"Primary Key(ExchangeID)) ENGINE=InnoDB DEFAULT CHARSET=utf8";
		db.direct_exec(sqlBuf.str().c_str());
		ostringstream sqlBuf2,valBuf;
		sqlBuf2<<"insert into exchanges values("
			<<":f1<char[16]>,"
			<<":f2<char[32]>,"
			<<":f3<int>)";
		size_t i=0;
		for (i=0;i<exchanges.size();i++)
		{
			EXCHANGE exchange=exchanges[i];
			string sql=string("select * from exchanges where ExchangeID='")+exchange.ExchangeID+"'";
			otl_stream o_query(50,sql.c_str(),db);
			if (!o_query.eof())
			{
				continue;
			}
			otl_stream o(1,sqlBuf2.str().c_str(),db);//插入时，第一个参数为1，参见otl的文档
			o<<exchange.ExchangeID
				<<exchange.ExchangeName
				<<exchange.ExchangeProperty;
		}
		iRet=i;
	}catch(otl_exception& p){
		last_error_msg=(char*)p.msg;
		DEBUG_METHOD();
		DEBUG_PRINTF("DatabaseOperator::StoreExchange发生错误:%s",p.msg);
		iRet=-1;
	}
	catch(std::exception& e)
	{
		last_error_msg=e.what();
		DEBUG_METHOD();
		DEBUG_PRINTF("DatabaseOperator::StoreExchange发生错误:%s",e.what());
		iRet=-1;
	}
	catch(...)
	{
		DEBUG_METHOD();
		DEBUG_MESSAGE("DatabaseOperator::StoreBasetable发生错误:未知的异常...");
		iRet=-1;
	}
	return iRet;
}

int DatabaseOperator::LoadExchange( vector<EXCHANGE>& exchanges )
{
	if (!m_bIsOK)
	{
		return 0;
	}
	try{
		DateTime currTime=DateTime::current_time();//由pInstrument传一个时间过来;
		ostringstream sql;
		sql<<"select ExchangeID,ExchangeName,ExchangeProperty from exchanges";
		EXCHANGE exchg={0};
		otl_stream o(256,sql.str().c_str(),db);
		while (!o.eof())
		{
			o>>exchg.ExchangeID>>exchg.ExchangeName>>exchg.ExchangeProperty;
			exchanges.push_back(exchg);
		}
	}catch(otl_exception& p){
		last_error_msg=(char*)p.msg;
		return -1;
	}
	catch(std::exception& e)
	{
		last_error_msg=e.what();
		return -1;
	}
	catch(...)
	{
		last_error_msg="未知错误";
		return -1;
	}
	return 1;
}
